﻿/**
 * Scene_Title
 * 
 * @version 2012.01.15
 * @author  Bruno Miguel de Oliveira Tamer <bmotamer@gmail.com>
 */

// TODO: GAME MODE

#region XNA Libraries

using Microsoft.Xna.Framework.Input;

#endregion

#region SDK Libraries

using main.sdk.audio;
using main.sdk.display;
using main.sdk.display.object2d;
using main.sdk.input;
using main.sdk.scene;
using main.sdk.utils.animations2D;
using Microsoft.Xna.Framework;
using System;

#endregion

namespace main.src.scene
{
    public sealed class Scene_Title : Scene_Base
    {

        #region Instance Variables

        /* Sprites */
        private Sprite  Background = new Sprite("RSC/Picture/Background");
        private Sprite  Player     = new Sprite("RSC/Picture/Soccer Player");
        private Sprite  Title      = new Sprite("RSC/Picture/Title");
        private Label[] Commands   = { new Label("Start"), new Label("Options"), new Label("Credits"), new Label("Exit") };
        private Sprite  Ball       = new Sprite("RSC/Picture/Ball");
        private uint    Step       = 0;
        private int     Index      = 0;

        /* Animadores (de torcida?) */
        private ParallelAnimator2D Animators = new ParallelAnimator2D();
        private SerialAnimator2D IntroAnimator = new SerialAnimator2D();
        private SerialAnimator2D MenuAnimator = new SerialAnimator2D();
        private SerialAnimator2D OutroAnimator = new SerialAnimator2D();

        #endregion

        #region Instance Methods

        /**
         * Inicializa a cena
         */
        public override void Start()
        {
            /* Cria a a abertura */
            SetupIntro();
        }

        /**
         * Cria a animação de abertura
         */
        private void SetupIntro()
        {
            /* Define a fase */
            Step = 0;

            /* Fase1: Animação do fundo */
            {
                /* Parametros iniciais */
                Background.Alpha = 0;
                Background.OX = Background.Width / 2;
                Background.OY = Background.Height / 2;
                Background.X = Program.Width / 2;
                Background.Y = Program.Height / 2;
                Background.Z = -1000;
                Background.Scale.X = 1.05f;
                Background.Scale.Y = 1.05f;

                /* Animador do fundo */
                Animator2D BackgroundAnimator = new Animator2D(Background);

                /* Animações do fundo */
                ParallelAnimation2D BackgroundParallel = new ParallelAnimation2D();
                BackgroundParallel.Add(new AlphaAnimation2D(255.0, 0.6, 2, false)); // Alpha para 255
                BackgroundParallel.Add(new ScaleAnimation2D(new Vector2(1, 1), 0.6, 2, false)); // Alpha para 255
                BackgroundAnimator.Add(BackgroundParallel);

                /* Adiciona o animador do fundo */
                IntroAnimator.Add(BackgroundAnimator);
            }

            /* Fase2: Jogador e Title */
            {
                /* Animadores em paralelo */
                ParallelAnimator2D AllAnimators = new ParallelAnimator2D();

                /**
                 * Jogador
                 */
                /* Parametros iniciais */
                Player.X = -Player.Width;
                Player.Y = Program.Height - Player.Height - 32;
                Player.Alpha = 0;

                /* Animador */
                Animator2D PlayerAnimator = new Animator2D(Player);

                /* Animação em paralela do jogador */
                ParallelAnimation2D PlayerParallel = new ParallelAnimation2D();
                PlayerParallel.Add(new AlphaAnimation2D(255.0, 0.6, 2, false)); // Transparencia
                PlayerParallel.Add(MoveAnimation2D.CreateX(Program.Width - Player.Width - 32, 0.6, 2, false)); // Posição
                PlayerAnimator.Add(PlayerParallel);

                /* Adiciona o animador do jogador */
                AllAnimators.Add(PlayerAnimator);

                /**
                 * Title 
                 */
                /* Parametros iniciais */
                Title.X = Program.Width;
                Title.Y = Program.Height / 4 - Title.Height;
                Title.Alpha = 0;

                /* Animador */
                Animator2D TitleAnimator = new Animator2D(Title);

                /* Animação em paralela do Title */
                ParallelAnimation2D TitleParallel = new ParallelAnimation2D();
                TitleParallel.Add(new AlphaAnimation2D(255.0, 0.6, 2, false)); // Transparencia
                TitleParallel.Add(MoveAnimation2D.CreateX((Program.Width - Title.Width) / 2, 0.6, 2, false)); // Posição
                TitleAnimator.Add(TitleParallel);

                /* Adiciona o animador do jogador */
                AllAnimators.Add(TitleAnimator);

                /**
                 * Bola
                 */
                /* Valores iniciais */
                Ball.OX = Ball.Width / 2;
                Ball.OY = Ball.Height / 2;
                Ball.X = Program.Width / 2;
                Ball.Y = Program.Height / 2;
                Ball.Scale.X = 64;
                Ball.Scale.Y = 64;
                Ball.Alpha = 0;

                /* Adiciona uma animação para a bola infinita de rotação */
                Animators.Add((new Animator2D(Ball)).Add(new RotationAnimation2D(-1, true)));

                /* Animador Bola */
                Animator2D BallAnimator = new Animator2D(Ball);
                /* Animações paralela para a bola */
                ParallelAnimation2D BallParallel = new ParallelAnimation2D();
                BallParallel.Add(new AlphaAnimation2D(255.0, 0.6, 3, false)); // Transparência
                BallParallel.Add(new MoveAnimation2D(new Vector2((float)32, (float)(Program.Height - Commands.Length * 48 - 16 + Index * 48)), 0.6, 2)); // Posição
                BallParallel.Add(new ScaleAnimation2D(new Vector2(1.0f, 1.0f), 0.6, 2)); // Zoom

                /* Adiciona a animação */
                BallAnimator.Add(BallParallel);

                /* Adiciona o animador da bola */
                AllAnimators.Add(BallAnimator);

                /**
                 * Comandos 
                 */
                for (uint i = 0; i < Commands.Length; i++)
                {
                    /* Parametros iniciais dos comandos */
                    Commands[i].OY = Commands[i].Height / 2;
                    Commands[i].X = -Commands[i].Width;
                    Commands[i].Y = Program.Height - Commands.Length * 48 - 16 + i * 48;
                    Commands[i].Outline = true;
                    Commands[i].OutlineSize = 2;

                    /* Animador do comando */
                    Animator2D CommandAnimator = new Animator2D(Commands[i]);
                    /* Adiciona uma pausa */
                    CommandAnimator.Add(new WaitAnimation2D(0.1 * i));
                    /* Adiciona uma animação de movimento em X */
                    CommandAnimator.Add(MoveAnimation2D.CreateX(32 + (i == Index ? 32 : 0), 0.6, 2));

                    /* Adiciona o animador do comando */
                    AllAnimators.Add(CommandAnimator);
                }

                /* Adiciona o animador dessa fase na intro */
                IntroAnimator.Add(AllAnimators);

            }
        }

        /**
         * Muda a origem sem mudar a posição real.
         */
        private void ChangeOrigin(Object2D obj, float NewOX, float NewOY)
        {
            obj.X += (NewOX - obj.OX);
            obj.Y += (NewOY - obj.OY);
            obj.OX = NewOX;
            obj.OY = NewOY;
        }

        /**
         * Cria a animação de saída.
         */
        private void SetupOutro()
        {
            /* Define a fase */
            Step = 2;

            /* Valores Iniciais */
            OutroAnimator = new SerialAnimator2D();

            /* Animadores  */
            ParallelAnimator2D AllAnimators = new ParallelAnimator2D();

            /* Animação do fundo */
            Animator2D BackgroundAnimator = new Animator2D(Background);
            ParallelAnimation2D BackZoomAlpha = new ParallelAnimation2D();
            BackZoomAlpha.Add(new ScaleAnimation2D(new Vector2(1.05f, 1.05f), 0.6, 2, false));
            BackZoomAlpha.Add(new AlphaAnimation2D(0, 0.6, 2, false));
            BackgroundAnimator.Add(BackZoomAlpha);
            AllAnimators.Add(BackgroundAnimator);

            /* Função de Animação dos Objetos */
            Func<Object2D, bool> SetupObject = obj =>
            {
                Animator2D ObjAnimator = new Animator2D(obj);

                /* Direção do movimento */
                Vector2 MoveDirection = new Vector2(Program.Width / 2 - obj.X, Program.Height / 2 - obj.Y);
                MoveDirection = Vector2.Multiply(MoveDirection, 0.1f);

                ParallelAnimation2D ObjParallel = new ParallelAnimation2D();

                ObjParallel.Add(new MoveAnimation2D(obj.Position - MoveDirection, 0.6, 2, false));
                ObjParallel.Add(new ScaleAnimation2D(new Vector2(1.1f, 1.1f), 0.6, 2, false));
                ObjParallel.Add(new AlphaAnimation2D(0, 0.6, 2, false));
                ObjAnimator.Add(ObjParallel);
                AllAnimators.Add(ObjAnimator);
                return true;
            };

            /* Adiciona a animação a todos os objetos */
            SetupObject(Player);
            SetupObject(Title);
            SetupObject(Ball);
            for (uint i = 0; i < Commands.Length; i++)
                SetupObject(Commands[i]);

            /* Adiciona os animadores ao animador final */
            OutroAnimator.Add(AllAnimators);
        }

        /**
         * Muda o indice do menu.
         */
        private void ChangeIndex(int NewIndex)
        {
            /* Cria os animadores */
            Animator2D OldCommandAnimator = new Animator2D(Commands[Index]);
            Animator2D NewCommandAnimator = new Animator2D(Commands[NewIndex]);
            Animator2D BallAnimator = new Animator2D(Ball);

            /* Adiciona as animações */
            OldCommandAnimator.Add(MoveAnimation2D.CreateX(32, 0.1, 2));
            NewCommandAnimator.Add(MoveAnimation2D.CreateX(64, 0.1, 2));
            BallAnimator.Add(MoveAnimation2D.CreateY(Program.Height - Commands.Length * 48 - 16 + NewIndex * 48, 0.1, 2));

            /* Adiciona os animadores ao animador do menu */
            MenuAnimator.Add((new ParallelAnimator2D()).Add(OldCommandAnimator).Add(NewCommandAnimator).Add(BallAnimator));

            /* Muda o indice */
            Index = NewIndex;
        }

        /**
         * Atualiza a cena
         */
        public override void Update()
        {
            /* Atualiza as animações básicas */
            Animators.Update(Program.Time.ElapsedGameTime.TotalSeconds);

            /* Atualiza dependendo do passo */
            switch (Step)
            {
                /* Introdução */
                case 0:
                    /* Atualiza o animador e muda de passo caso tenha terminado */
                    IntroAnimator.Update(Program.Time.ElapsedGameTime.TotalSeconds);
                    if (IntroAnimator.Finished())
                        Step = 1;
                    break;

                /* Menu */
                case 1:
                    /* Atualiza o menu */
                    MenuAnimator.Update(Program.Time.ElapsedGameTime.TotalSeconds);
                    if (MenuAnimator.Active())
                        break;

                    /* Verifica entrada de tecla */
                    if (Input.Trigger(Keys.Enter))
                        SetupOutro();
                    else if (Input.Trigger(Keys.Down))
                        ChangeIndex((Index + 1) % Commands.Length);
                    else if (Input.Trigger(Keys.Up))
                        ChangeIndex((Index + (Commands.Length - 1)) % Commands.Length);
                    break;

                /* Saida do Title*/
                case 2:
                    /* Atualiza o animador */
                    OutroAnimator.Update(Program.Time.ElapsedGameTime.TotalSeconds);

                    /* Caso tenha acabado, realiza a ação dependendo do indice */
                    if (OutroAnimator.Finished())
                    {
                        switch (Index)
                        {
                            case 0:
                                Scene.Set(new Scene_Play());
                                break;
                            case 1:
                                Scene.Set(new Scene_Option());
                                break;
                            case 2:
                                Scene.Set(new Scene_Credits());
                                break;
                            case 3:
                                Scene.Set(null);
                                break;

                        }
                    }
                    break;
            }
        }

        /**
         * Termina a cena.
         */
        public override void Terminate()
        {
            Background.Dispose();
            Player.Dispose();
            Title.Dispose();
            Ball.Dispose();
            foreach (Label command in Commands)
                command.Dispose();
        }

        #endregion
    }

}